# 导入程序运行必须模块
import sys
# PyQt5中使用的基本控件都在PyQt5.QtWidgets模块中
from PyQt5.QtWidgets import QApplication, QMainWindow, QMessageBox, QLabel
from PyQt5.QtGui import QImage, QPixmap
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
import numpy as np
import matplotlib.pyplot as plt
from scipy.spatial.transform import Rotation as R
import math
from DRR_GUI.ui.transform_view import Ui_Form
from DRR_generator.the_main import Projector

# # 导入投影模块
# from DRR_simulation import VoxelToProjection

plt.rcParams["font.sans-serif"] = ["SimHei"]  # 设置字体
plt.rcParams["axes.unicode_minus"] = False


class MyMainForm(QMainWindow, Ui_Form):
    def __init__(self, parent=None, CT_path="C:/Users/adminTKJ/Desktop/CT_投影/CT_data"):
        super(MyMainForm, self).__init__(parent)
        self.setupUi(self)
        # 添加退出按钮信号和槽。调用close函数
        self.exit.clicked.connect(self.close)
        # 创建投影画布
        self.project_fig = QLabel()
        self.verticalLayout.addWidget(self.project_fig)
        # 添加初始化按钮
        self.init.clicked.connect(self.draw)
        # 添加绕x轴的旋转
        self.sp_rx.valueChanged.connect(lambda: self.sp_value_change('rx'))
        # 设定x轴输入角度的信号
        self.angle_x.returnPressed.connect(lambda: self.text_value_change('rx'))
        # 添加绕y轴的旋转
        self.sp_ry.valueChanged.connect(lambda: self.sp_value_change('ry'))
        # 设定y轴输入角度的信号
        self.angle_y.returnPressed.connect(lambda: self.text_value_change('ry'))
        # 添加绕z轴的旋转
        self.sp_rz.valueChanged.connect(lambda: self.sp_value_change('rz'))
        # 设定z轴输入角度的信号
        self.angle_z.returnPressed.connect(lambda: self.text_value_change('rz'))
        # 添加绕x轴的平移
        self.sp_tx.valueChanged.connect(lambda: self.sp_value_change('tx'))
        # 设定x轴输入平移的信号
        self.trans_x.returnPressed.connect(lambda: self.text_value_change('tx'))
        # 添加绕y轴的平移
        self.sp_ty.valueChanged.connect(lambda: self.sp_value_change('ty'))
        # 设定y轴输入平移的信号
        self.trans_y.returnPressed.connect(lambda: self.text_value_change('ty'))
        # 添加绕z轴的平移
        self.sp_tz.valueChanged.connect(lambda: self.sp_value_change('tz'))
        # 设定z轴输入平移的信号
        self.trans_z.returnPressed.connect(lambda: self.text_value_change('tz'))
        # 导入CT投影体素
        self.projector = Projector()
        self.projector.load_ct_images(directory=CT_path)
        # 设定全局使用的角度旋转和平移量
        self.rx = 0
        self.ry = 90
        self.rz = 180
        self.tx = 0
        self.ty = 0
        self.tz = 0

    # 当滑动条中的值发生变化之后
    def sp_value_change(self, mode):
        if mode == 'rx':
            # 当滑块移动之后，对应的数字就会显示在上方
            self.angle_x.setText(str(self.sp_rx.value()))
            self.rx = self.sp_rx.value()
        if mode == 'ry':
            # 当滑块移动之后，对应的数字就会显示在上方
            self.angle_y.setText(str(self.sp_ry.value()))
            self.ry = self.sp_ry.value()
        if mode == 'rz':
            # 当滑块移动之后，对应的数字就会显示在上方
            self.angle_z.setText(str(self.sp_rz.value()))
            self.rz = self.sp_rz.value()
        if mode == 'tx':
            # 当滑块移动之后，对应的数字就会显示在上方
            self.trans_x.setText(str(self.sp_tx.value()))
            self.tx = self.sp_tx.value()
        if mode == 'ty':
            # 当滑块移动之后，对应的数字就会显示在上方
            self.trans_y.setText(str(self.sp_ty.value()))
            self.ty = self.sp_ty.value()
        if mode == 'tz':
            # 当滑块移动之后，对应的数字就会显示在上方
            self.trans_z.setText(str(self.sp_tz.value()))
            self.tz = self.sp_tz.value()
        # 显示对应的drr图片
        self.display(self.rx, self.ry, self.rz, self.tx, self.ty, self.tz)

    # 当绕x轴旋转的指令被触发的时候，执行旋转命令
    def text_value_change(self, mode):
        self.verticalLayout_14.blockSignals(True)
        if mode == 'rx':
            # 设置滚动条的值与之对应
            self.sp_rx.setValue(int(self.angle_x.text()))
            self.rx = int(self.angle_x.text())
        if mode == 'ry':
            # 设置滚动条的值与之对应
            self.sp_ry.setValue(int(self.angle_y.text()))
            self.ry = int(self.angle_y.text())
        if mode == 'rz':
            # 设置滚动条的值与之对应
            self.sp_rz.setValue(int(self.angle_z.text()))
            self.rz = int(self.angle_z.text())
        if mode == 'tx':
            # 设置滚动条的值与之对应
            self.sp_tx.setValue(int(self.trans_x.text()))
            self.tx = int(self.trans_x.text())
        if mode == 'ty':
            # 设置滚动条的值与之对应
            self.sp_ty.setValue(int(self.trans_y.text()))
            self.ty = int(self.trans_y.text())
        if mode == 'tz':
            # 设置滚动条的值与之对应
            self.sp_tz.setValue(int(self.trans_z.text()))
            self.tz = int(self.trans_z.text())
        self.display(self.rx, self.ry, self.rz, self.tx, self.ty, self.tz)
        self.verticalLayout_14.blockSignals(False)

    def display(self, _rx, _ry, _rz, _tx, _ty, _tz):
        self.projector.set_rotation(angle_x=_rx, angle_y=_ry, angle_z=_rz)
        init_image = self.projector.project(tx=_tx, ty=_ty, tz=_tz).reshape(128, 128)
        im = QImage(init_image, init_image.shape[1], init_image.shape[0],
                    init_image.shape[1],
                    QImage.Format_Indexed8)
        pix = QPixmap(im)
        self.project_fig.setPixmap(pix)
        self.project_fig.setScaledContents(True)
        self.project_fig.show()

    def draw(self):
        # 显示初始化
        # 旋转
        self.angle_x.setText(str(0))
        self.sp_rx.setValue(0)
        self.angle_y.setText(str(90))
        self.sp_ry.setValue(90)
        self.angle_z.setText(str(180))
        self.sp_rz.setValue(180)
        # 平移
        self.trans_x.setText(str(0))
        self.sp_tx.setValue(0)
        self.trans_y.setText(str(0))
        self.sp_ty.setValue(0)
        self.trans_z.setText(str(0))
        self.sp_tz.setValue(0)
        # 实际参数初始化
        self.rx, self.ry, self.rz, self.tx, self.ty, self.tz = 0, 90, 180, 0, 0, 0
        self.display(self.rx, self.ry, self.rz, self.tx, self.ty, self.tz)


if __name__ == "__main__":
    # 固定的，PyQt5程序都需要QApplication对象。sys.argv是命令行参数列表，确保程序可以双击运行
    app = QApplication(sys.argv)
    # 初始化
    myWin = MyMainForm()
    myWin.setFixedSize(844, 442)
    # 将窗口控件显示在屏幕上
    myWin.show()
    # 程序运行，sys.exit方法确保程序完整退出。
    sys.exit(app.exec_())
